home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-06-25 | 19.2 KB | 772 lines | [TEXT/CWIE] |
- // ===========================================================================
- // COutOfContextApp.cp ©1999 Eric Traut
- // ===========================================================================
-
- #include "COutOfContextApp.h"
- #include "CShadowWindow.h"
- #include "TerminationUtils.h"
-
- #include <LGrowZone.h>
- #include <PP_Messages.h>
- #include <PP_Resources.h>
- #include <PPobClasses.h>
- #include <UDrawingState.h>
- #include <UMemoryMgr.h>
- #include <URegistrar.h>
-
- #include <LWindow.h>
- #include <LCaption.h>
-
- #include <LowMem.h>
-
- #include <Gestalt.h>
- #include <Patches.h>
- #include <Traps.h>
- #include <Resources.h>
- #include <MixedMode.h>
-
- #include "WaitNextEventPatch.h"
- #include "CRebootBehavior.h"
- #include "CPongGameBehavior.h"
-
- #define SUPPORT_PIG_LATIN 0
-
- const PP_PowerPlant::ResIDT wind_SampleWindow = 128;
-
- #if SUPPORT_PIG_LATIN
- const PP_PowerPlant::ResIDT menu_ContextMenu1 = 6788;
- const PP_PowerPlant::ResIDT menu_ContextMenu2 = 234;
- #else
- const PP_PowerPlant::ResIDT menu_ContextMenu1 = 6789;
- #endif
-
- enum
- {
- kContextMenu1HelpIndex = 1,
- kContextMenu1Divider1,
- kContextMenu1GaussianBlur,
- kContextMenu1Invert,
- kContextMenu1FlipHorizontal,
- kContextMenu1FlipVertical,
- kContextMenu1Compress,
- kContextMenu1Duplicate,
- kContextMenu1Restore,
- #if SUPPORT_PIG_LATIN
- kContextMenu1Divider2,
- kContextMenuIDCharSet,
- #endif
- kContextMenu1Divider3,
- kContextMenu1AdjustVBlank,
- kContextMenu1NextSlide,
- kContextMenu1NewGame,
- kContextMenu1Divider4,
- kContextMenu1Restart,
-
- kContextMenu2Latin = 1,
- kContextMenu2PigLatin
- };
-
- COutOfContextApp * COutOfContextApp::sOutOfContextApp = NULL;
-
- GetNextEventFilterUPP COutOfContextApp::sChainedGNEFilter = NULL;
- GetNextEventFilterUPP COutOfContextApp::sNewGNEFilter = NULL;
- Ptr COutOfContextApp::sGNEJumpIsland = NULL;
- Boolean COutOfContextApp::sGNEPatchInstalled = false;
- THz COutOfContextApp::sAppZone = NULL;
- Boolean COutOfContextApp::sWNEPatchInstalled = false;
- Handle COutOfContextApp::sWNEPatchHandle = NULL;
- MenuHandle COutOfContextApp::sContextMenu1 = NULL;
- MenuHandle COutOfContextApp::sContextMenu2 = NULL;
- SndChannelPtr COutOfContextApp::sSoundChannel = NULL;
-
-
- class StZoneSaver
- {
- public:
- StZoneSaver(THz inNewZone)
- {
- mSavedZone = ::GetZone();
- ::SetZone(inNewZone);
- }
-
- ~StZoneSaver(void)
- {
- ::SetZone(mSavedZone);
- }
-
- private:
- THz mSavedZone;
- };
-
-
- // ===========================================================================
- // • Main Program
- // ===========================================================================
-
- int
- main(void)
- {
- SetDebugThrow_(PP_PowerPlant::debugAction_Debugger);
- SetDebugSignal_(PP_PowerPlant::debugAction_Debugger);
-
- PP_PowerPlant::InitializeHeap(3);
- PP_PowerPlant::UQDGlobals::InitializeToolbox(&qd);
-
- new PP_PowerPlant::LGrowZone(20000);
- COutOfContextApp theApp;
- theApp.Run();
-
- return 0;
- }
-
-
- // ---------------------------------------------------------------------------
- // • COutOfContextApp
- // ---------------------------------------------------------------------------
-
- COutOfContextApp::COutOfContextApp(void)
- {
- RegisterClass_(PP_PowerPlant::LWindow);
- RegisterClass_(PP_PowerPlant::LCaption);
-
- sAppZone = ::GetZone();
- sWNEPatchHandle = ::Get1Resource(kWNEPatchRsrcType, kWNEPatchRsrcID);
- Assert_(sWNEPatchHandle != NULL);
-
- ::DetachResource(sWNEPatchHandle);
- ::MoveHHi(sWNEPatchHandle);
- ::HLock(sWNEPatchHandle);
-
- sContextMenu1 = ::GetMenu(menu_ContextMenu1);
- Assert_(sContextMenu1 != NULL);
-
- #if SUPPORT_PIG_LATIN
- sContextMenu2 = ::GetMenu(menu_ContextMenu2);
- Assert_(sContextMenu2 != NULL);
- #endif SUPPORT_PIG_LATIN
-
- OSErr err;
- err = ::SndNewChannel(&sSoundChannel, sampledSynth, initMono + initNoInterp + initNoDrop, NULL);
- Assert_(err == noErr);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ~COutOfContextApp
- // ---------------------------------------------------------------------------
-
- COutOfContextApp::~COutOfContextApp(void)
- {
- }
-
-
- // ---------------------------------------------------------------------------
- // • StartUp
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::StartUp(void)
- {
- sOutOfContextApp = this;
-
- InstallTearDownProc(OutOfContextTearDownProc);
- InstallGNEFilter();
-
- CRebootBehavior::Initialize(sSoundChannel);
- CPongGameBehavior::Initialize(sSoundChannel);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ObeyCommand
- // ---------------------------------------------------------------------------
-
- Boolean
- COutOfContextApp::ObeyCommand(
- PP_PowerPlant::CommandT inCommand,
- void * ioParam)
- {
- Boolean cmdHandled = true;
-
- switch (inCommand)
- {
- case PP_PowerPlant::cmd_New:
- PP_PowerPlant::LWindow *theWindow =
- PP_PowerPlant::LWindow::CreateWindow(wind_SampleWindow, this);
- ThrowIfNULL_(theWindow);
-
- theWindow->Show();
- break;
-
- default:
- cmdHandled = PP_PowerPlant::LApplication::ObeyCommand(inCommand, ioParam);
- break;
- }
-
- return cmdHandled;
- }
-
-
- // ---------------------------------------------------------------------------
- // • FindCommandStatus
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::FindCommandStatus(
- PP_PowerPlant::CommandT inCommand,
- Boolean & outEnabled,
- Boolean & outUsesMark,
- PP_PowerPlant::Char16 & outMark,
- Str255 outName)
- {
-
- switch (inCommand)
- {
- case PP_PowerPlant::cmd_New:
- outEnabled = true;
- break;
-
- default:
- LApplication::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
- break;
- }
- }
-
-
-
- // ---------------------------------------------------------------------------
- // • OutOfContextTearDownProc [static]
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::OutOfContextTearDownProc(void)
- {
- if (COutOfContextApp::sOutOfContextApp != NULL)
- COutOfContextApp::sOutOfContextApp->TearDownApp();
- }
-
-
- // ---------------------------------------------------------------------------
- // • TearDownApp
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::TearDownApp(void)
- {
- if (sSoundChannel != NULL)
- ::SndDisposeChannel(sSoundChannel, true);
-
- TearDownShadowWindows();
- RemoveGNEFilter();
- DeinstallWNEPatch();
- }
-
-
- // ---------------------------------------------------------------------------
- // • AttemptQuitSelf
- // ---------------------------------------------------------------------------
-
- Boolean
- COutOfContextApp::AttemptQuitSelf(
- SInt32 inSaveOption)
- {
- #pragma unused (inSaveOption)
-
- TearDownApp();
- sOutOfContextApp = NULL;
-
- return true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • HandleContextualMenuClick
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::HandleContextualMenuClick(
- EventRecord * ioEvent,
- Boolean * ioResult)
- {
- ThrowIfNULL_(sContextMenu1);
-
- #if SUPPORT_PIG_LATIN
- ThrowIfNULL_(sContextMenu2);
- #endif
-
- WindowPtr clickedWindow;
- SInt16 clickedPart;
-
- clickedPart = ::FindWindow(ioEvent->where, &clickedWindow);
- if (clickedWindow != NULL && clickedPart == inContent)
- {
- CShadowWindow * shadowWindow;
- shadowWindow = LookUpWindowInShadowList(reinterpret_cast<CWindowRecord *>(clickedWindow));
-
- if (shadowWindow != NULL)
- {
- ::InsertMenu(sContextMenu1, hierMenu);
-
- #if SUPPORT_PIG_LATIN
- ::InsertMenu(sContextMenu2, hierMenu);
- #endif
-
- Boolean enableRestore = shadowWindow->ShouldEnableRestoreMenu();
-
- if (enableRestore)
- ::EnableItem(sContextMenu1, kContextMenu1Restore);
- else
- ::DisableItem(sContextMenu1, kContextMenu1Restore);
-
- ::EnableItem(sContextMenu1, kContextMenu1GaussianBlur);
- ::EnableItem(sContextMenu1, kContextMenu1Invert);
- ::EnableItem(sContextMenu1, kContextMenu1FlipHorizontal);
- ::EnableItem(sContextMenu1, kContextMenu1FlipVertical);
- #if SUPPORT_PIG_LATIN
- ::EnableItem(sContextMenu1, kContextMenuIDCharSet);
- #endif
- ::EnableItem(sContextMenu1, kContextMenu1Compress);
- ::EnableItem(sContextMenu1, kContextMenu1AdjustVBlank);
- ::EnableItem(sContextMenu1, kContextMenu1Duplicate);
- ::EnableItem(sContextMenu1, kContextMenu1NextSlide);
- ::EnableItem(sContextMenu1, kContextMenu1NewGame);
- ::EnableItem(sContextMenu1, kContextMenu1Restart);
-
- SInt32 result;
- result = ::PopUpMenuSelect(sContextMenu1, ioEvent->where.v, ioEvent->where.h, 0);
-
- #if SUPPORT_PIG_LATIN
- ::DeleteMenu(menu_ContextMenu2);
- #endif
- ::DeleteMenu(menu_ContextMenu1);
-
- switch (HiWord(result))
- {
- case menu_ContextMenu1:
- switch (LoWord(result))
- {
- case kContextMenu1GaussianBlur:
- shadowWindow->SetIdleMenuAction(kShadowActionBlur);
- break;
-
- case kContextMenu1Invert:
- shadowWindow->SetIdleMenuAction(kShadowActionInvert);
- break;
-
- case kContextMenu1FlipHorizontal:
- shadowWindow->SetIdleMenuAction(kShadowActionFlipH);
- break;
-
- case kContextMenu1FlipVertical:
- shadowWindow->SetIdleMenuAction(kShadowActionFlipV);
- break;
-
- case kContextMenu1Restore:
- shadowWindow->SetIdleMenuAction(kShadowActionRestore);
- break;
-
- case kContextMenu1Compress:
- shadowWindow->SetIdleMenuAction(kShadowActionCrash);
- break;
-
- case kContextMenu1AdjustVBlank:
- shadowWindow->SetIdleMenuAction(kShadowActionVBlank);
- break;
-
- case kContextMenu1Duplicate:
- shadowWindow->SetIdleMenuAction(kShadowActionDuplicate);
- break;
-
- case kContextMenu1NextSlide:
- shadowWindow->SetIdleMenuAction(kShadowActionNextSlide);
- break;
-
- case kContextMenu1NewGame:
- shadowWindow->SetIdleMenuAction(kShadowActionGame);
- break;
-
- case kContextMenu1Restart:
- shadowWindow->SetIdleMenuAction(kShadowActionReboot);
- break;
- }
- break;
-
- #if SUPPORT_PIG_LATIN
- case menu_ContextMenu2:
- switch (LoWord(result))
- {
- case kContextMenu2Latin:
- shadowWindow->SetIdleMenuAction(kShadowActionRestore);
- break;
-
- case kContextMenu2PigLatin:
- shadowWindow->SetIdleMenuAction(kShadowActionPigLatin);
- break;
- }
- break;
- #endif
- }
-
- *ioResult = false;
- }
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DoFinderGNEFilter
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::DoFinderGNEFilter(
- EventRecord * ioEvent,
- Boolean * ioResult)
- {
- // Temporarily set the zone to our app. We don't want to
- // be allocating out of our "guest's" heap.
- StZoneSaver saveZone(sAppZone);
-
- try
- {
- // Update the list of all the open windows in the Finder
- UpdateShadowWindowList();
-
- if (ioEvent->what == mouseDown &&
- (ioEvent->modifiers & controlKey) != 0)
- {
- HandleContextualMenuClick(ioEvent, ioResult);
- }
- else
- {
- WindowPtr frontWindow = ::FrontWindow();
- CShadowWindow * frontShadow = LookUpWindowInShadowList(reinterpret_cast<CWindowRecord *>(frontWindow));
-
- if (frontShadow != NULL)
- frontShadow->HandleEvent(ioEvent, ioResult);
-
- // Give each of the shadow windows some time
- GiveShadowWindowsTime(true);
- }
- }
- catch (...)
- {
- // Don't throw any exceptions through the GNE filter
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • GNEFilterPatch [static]
- // ---------------------------------------------------------------------------
-
- pascal void
- COutOfContextApp::GNEFilterPatch(
- EventRecord * ioEvent,
- Boolean * ioResult)
- {
- OSErr error;
- ProcessInfoRec processInfo;
- ProcessSerialNumber psn;
-
- error = ::GetCurrentProcess(&psn);
- Assert_(error == noErr);
-
- processInfo.processInfoLength = sizeof(processInfo);
- processInfo.processName = NULL;
- processInfo.processAppSpec = NULL;
- error = ::GetProcessInformation(&psn, &processInfo);
- Assert_(error == noErr);
-
- // Is this the Finder? If so, we've got some things to do.
- if (processInfo.processSignature == 'MACS')
- {
- if (!sWNEPatchInstalled)
- InstallWNEPatch();
-
- COutOfContextApp::sOutOfContextApp->DoFinderGNEFilter(ioEvent, ioResult);
- }
-
- // Call through to the next one in the chain
- if (sChainedGNEFilter != NULL)
- CallGetNextEventFilterProc(sChainedGNEFilter, ioEvent, ioResult);
- }
-
-
- // ---------------------------------------------------------------------------
- // • InstallWNEPatch [static]
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::InstallWNEPatch(void)
- {
- if (!sWNEPatchInstalled)
- {
- sWNEPatchInstalled = true;
-
- WNEPatchInfo * wnePatchInfo;
- // First, see if there's already a copy of the
- // patch hanging around in the system heap. If so,
- // just turn it on.
- if (Gestalt(gestaltWNEPatch, (long *)&wnePatchInfo) == noErr)
- {
- // See if the Finder's WNE is still wired to our patch.
- // If so, we'll just enable it.
- UniversalProcPtr curWNEPatch = ::GetToolTrapAddress(_WaitNextEvent);
- if (curWNEPatch == (UniversalProcPtr)wnePatchInfo->fPatchEntry)
- {
- wnePatchInfo->fPatchActive = true;
- return;
- }
- }
-
- // Call the patch to have it install itself
- (void) CallUniversalProc( (UniversalProcPtr)*sWNEPatchHandle,
- kPascalStackBased);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • DeinstallWNEPatch [static]
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::DeinstallWNEPatch(void)
- {
- // We can't unpatch ourselves here, but we can
- // turn ourselves off.
- if (sWNEPatchInstalled)
- {
- sWNEPatchInstalled = false;
-
- WNEPatchInfo * wnePatchInfo;
-
- // First, see if there's already a copy of the
- // patch hanging around in the system heap. If so,
- // just turn it on.
- if (Gestalt(gestaltWNEPatch, (long *)&wnePatchInfo) == noErr)
- wnePatchInfo->fPatchActive = false;
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • InstallGNEFilter
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::InstallGNEFilter(void)
- {
- sGNEJumpIsland = ::NewPtrSysClear(6);
- ThrowIfNULL_(sGNEJumpIsland);
-
- sNewGNEFilter = NewGetNextEventFilterProc(COutOfContextApp::GNEFilterPatch);
- ThrowIfNULL_(sNewGNEFilter);
-
- // Fill in the jump instruction (JMP $XXXXXXXXL)
- *(UInt16 *)sGNEJumpIsland = 0x4EF9;
- *(GetNextEventFilterUPP *)(sGNEJumpIsland + 2) = sNewGNEFilter;
-
- // We just modified code, so we need to flush the cache
- Flush68KCodeCache();
-
- sChainedGNEFilter = LMGetGNEFilter();
- LMSetGNEFilter((GetNextEventFilterUPP)sGNEJumpIsland);
-
- sGNEPatchInstalled = true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • RemoveGNEFilter
- // ---------------------------------------------------------------------------
-
- void
- COutOfContextApp::RemoveGNEFilter(void)
- {
- if (sGNEPatchInstalled)
- {
- // Can we just unchain, or do we need to
- // leave the island in place?
- if (LMGetGNEFilter() == (GetNextEventFilterUPP)sGNEJumpIsland)
- {
- LMSetGNEFilter(sChainedGNEFilter);
-
- ::DisposeRoutineDescriptor(sNewGNEFilter);
- ::DisposePtr((Ptr)sGNEJumpIsland);
- }
- else
- {
- *(GetNextEventFilterUPP *)(sGNEJumpIsland + 2) = sChainedGNEFilter;
-
- // We just modified code, so we need to flush the cache
- Flush68KCodeCache();
- }
-
- sGNEPatchInstalled = false;
- }
- }
-
-
- /*------------------------------------------------------------------
- Flush68KCodeCache
-
- This function flushes the 68K emulator code cache.
- ------------------------------------------------------------------*/
-
- void
- COutOfContextApp::Flush68KCodeCache(void)
- {
- static const UInt16 s68KCode[] =
- {
- 0xA0BD, // vCacheFlush
- 0x4E75 // RTS
- };
-
- CallUniversalProc((UniversalProcPtr)s68KCode, kPascalStackBased);
- }
-
-
- /*------------------------------------------------------------------
- UpdateShadowWindowList
-
- Creates a list of shadow window objects.
- ------------------------------------------------------------------*/
-
- void
- COutOfContextApp::UpdateShadowWindowList(void)
- {
- TArrayIterator<CShadowWindow *> iterator(mShadowWindowList);
- CShadowWindow * curWindow;
-
- // Clear all the "visited" flags
- while (iterator.Next(curWindow))
- curWindow->ClearVisitedFlag();
-
- // Add in all of the new windows
- CWindowRecord * curMacWindow;
- curMacWindow = reinterpret_cast<CWindowRecord *>(LMGetWindowList());
-
- while (curMacWindow != NULL)
- {
- // Do we already know about this window?
- curWindow = LookUpWindowInShadowList(curMacWindow);
-
- if (curWindow == NULL)
- {
- curWindow = new CShadowWindow(curMacWindow);
- if (curWindow != NULL)
- mShadowWindowList.AddItem(curWindow);
- }
-
- if (curWindow != NULL)
- curWindow->SetVisitedFlag();
-
- // Go to next window in Mac's window list
- curMacWindow = reinterpret_cast<CWindowRecord *>(curMacWindow->nextWindow);
- }
-
- // Delete all the unvisited flags
- iterator.ResetTo(LArrayIterator::from_Start);
- while (iterator.Next(curWindow))
- {
- if (!curWindow->WasVisited())
- {
- delete curWindow;
- mShadowWindowList.RemoveItemsAt(1, iterator.GetCurrentIndex());
- }
- }
- }
-
-
- /*------------------------------------------------------------------
- LookUpWindowInShadowList
-
- Searches the shadow list for a specified Mac window.
- ------------------------------------------------------------------*/
-
- CShadowWindow *
- COutOfContextApp::LookUpWindowInShadowList(
- const CWindowRecord * inMacWindow)
- {
- TArrayIterator<CShadowWindow *> iterator(mShadowWindowList);
- CShadowWindow * curWindow;
-
- // Clear all the "visited" flags
- while (iterator.Next(curWindow))
- {
- if (curWindow->GetMacWindow() == inMacWindow)
- return curWindow;
- }
-
- return NULL;
- }
-
-
- /*------------------------------------------------------------------
- GiveShadowWindowsTime
-
- Calles each of the installed shadow window objects to
- give them time to "do their stuff".
- ------------------------------------------------------------------*/
-
- void
- COutOfContextApp::GiveShadowWindowsTime(
- Boolean inGNETime)
- {
- // Temporarily set the zone to our app. We don't want to
- // be allocating out of our "guest's" heap.
- StZoneSaver saveZone(sAppZone);
-
- StGDeviceSaver savedPort;
- TArrayIterator<CShadowWindow *> iterator(mShadowWindowList);
- CShadowWindow * curWindow;
-
- while (iterator.Next(curWindow))
- curWindow->DoIdleTask(inGNETime);
- }
-
-
- /*------------------------------------------------------------------
- LookUpShadowWindow
-
- Searches the shadow window list looking for a match.
- ------------------------------------------------------------------*/
-
- CShadowWindow *
- COutOfContextApp::LookUpShadowWindow(
- CWindowRecord * inMacWindow)
- {
- TArrayIterator<CShadowWindow *> iterator(mShadowWindowList);
- CShadowWindow * curWindow;
-
- while (iterator.Next(curWindow))
- {
- if (curWindow->GetMacWindow() == inMacWindow)
- return curWindow;
- }
-
- return NULL;
- }
-
-
- /*------------------------------------------------------------------
- TearDownShadowWindows
-
- Detaches from all the windows. Let's hope that the window
- list has not changed since the last time we synched up!
- ------------------------------------------------------------------*/
-
- void
- COutOfContextApp::TearDownShadowWindows(void)
- {
- TArrayIterator<CShadowWindow *> iterator(mShadowWindowList);
- CShadowWindow * curWindow;
-
- while (iterator.Next(curWindow))
- curWindow->DetachBehavior();
- }
-
-
-
-